/* hal_gpio.c */

#include "hal_gpio.h"

void GPIO_SetPinMux(GPIO_Type * GPIOx, uint32_t pins, GPIO_PinMux_Type mux)
{
    switch (mux)
    {
        case GPIO_PinMux_GPIO:
            GPIOx->EN0_SET = pins;
            GPIOx->EN1_CLR = pins;
            GPIOx->EN2_CLR = pins;
            break;

        case GPIO_PinMux_AF_1:
            GPIOx->EN0_CLR = pins;
            GPIOx->EN1_CLR = pins;
            GPIOx->EN2_CLR = pins;
            break;

        case GPIO_PinMux_AF_2:
            GPIOx->EN0_CLR = pins;
            GPIOx->EN1_SET = pins;
            GPIOx->EN2_CLR = pins;
            break;

        default:
            break;
    }
}

bool GPIO_ReadInDataBit(GPIO_Type * GPIOx, uint32_t pins)
{
    return (GPIOx->IN & pins);
}

uint32_t GPIO_ReadInData(GPIO_Type * GPIOx)
{
    return GPIOx->IN;
}

void GPIO_WriteBit(GPIO_Type * GPIOx, uint32_t pins, uint32_t val)
{
    if (val == 0u)
    {
        GPIOx->OUT_CLR = pins;
    }
    else
    {
        GPIOx->OUT_SET = pins;
    }
}

void GPIO_WriteBits(GPIO_Type * GPIOx, uint32_t val)
{
    GPIOx->OUT = val;
}

void GPIO_SetPinMode(GPIO_Type * GPIOx, uint32_t pins, GPIO_PinMode_Type mode, bool af_volt)
{
    switch (mode)
    {
        case GPIO_PinMode_HighImpedance:
            GPIOx->PADCTRL1 &= ~pins;
            GPIOx->PADCTRL0 &= ~pins;
            break;

        case GPIO_PinMode_PullupWeak:
            GPIOx->PADCTRL1 &= ~pins;
            GPIOx->PADCTRL0 |=  pins;
            GPIOx->PS &= ~pins;
            break;

        case GPIO_PinMode_PullUp:
            GPIOx->PADCTRL1 &= ~pins;
            GPIOx->PADCTRL0 |=  pins;
            GPIOx->PS |= pins;
            break;

        case GPIO_PinMode_PullDownWeak:
            GPIOx->PADCTRL1 |= pins;
            GPIOx->PADCTRL0 &= ~pins;
            GPIOx->PS &= ~pins;
            break;

        case GPIO_PinMode_PullDown:
            GPIOx->PADCTRL1 |= pins;
            GPIOx->PADCTRL0 &= ~pins;
            GPIOx->PS |= pins;
            break;

        case GPIO_PinMode_Out_DriverStrength_0:
            GPIOx->DS1 &= ~pins;
            GPIOx->DS0 &= ~pins;
            break;

        case GPIO_PinMode_Out_DriverStrength_1:
            GPIOx->DS1 &= ~pins;
            GPIOx->DS0 |=  pins;
            break;

        case GPIO_PinMode_Out_DriverStrength_2:
            GPIOx->DS1 |=  pins;
            GPIOx->DS0 &= ~pins;
            break;

        case GPIO_PinMode_Out_DriverStrength_3:
            GPIOx->DS1 |=  pins;
            GPIOx->DS0 |=  pins;
            break;

        default:
            break;
    }

    if (af_volt)
    {
        GPIOx->VSSEL |= pins;
    }
    else
    {
        GPIOx->VSSEL &= ~pins;
    }
}

void GPIO_SetDirection(GPIO_Type * GPIOx, uint32_t pins, bool output)
{
    if (output)
    {
        GPIOx->INEN &= ~pins;
        GPIOx->OUTEN |= pins;
    }
    else
    {
        GPIOx->OUTEN &= ~pins;
        GPIOx->INEN |= pins;
    }
}

uint32_t GPIO_GetInterruptStatus(GPIO_Type * GPIOx)
{
    return GPIOx->INTFL;
}

void GPIO_ClearInterruptStatus(GPIO_Type * GPIOx, uint32_t flags)
{
    GPIOx->INTFL_CLR = flags;
}

void GPIO_EnableInterrupts(GPIO_Type * GPIOx, uint32_t flags, bool enable)
{
    if (enable)
    {
        GPIOx->INTEN_SET = flags;
    }
    else
    {
        GPIOx->INTEN_CLR = flags;
    }
}

uint32_t GPIO_GetEnabledInterrupts(GPIO_Type * GPIOx)
{
    return GPIOx->INTEN;
}


void GPIO_SetInterruptEvent(GPIO_Type * GPIOx, uint32_t pins, GPIO_InterruptMode_Type mode)
{
    switch (mode)
    {
        case GPIO_InterruptMode_LevelLow:
            GPIOx->INTMODE &= ~pins;
            GPIOx->INTPOL &= ~pins;
            GPIOx->DUALEDGE &= ~pins;
            break;

        case GPIO_InterruptMode_LevelHigh:
            GPIOx->INTMODE &= ~pins;
            GPIOx->INTPOL |= pins;
            GPIOx->DUALEDGE &= ~pins;
            break;

        case GPIO_InterruptMode_EdgeFalling:
            GPIOx->INTMODE |= pins;
            GPIOx->INTPOL &= ~pins;
            GPIOx->DUALEDGE &= ~pins;
            break;

        case GPIO_InterruptMode_EdgeRising:
            GPIOx->INTMODE |= pins;
            GPIOx->INTPOL |= pins;
            GPIOx->DUALEDGE &= ~pins;
            break;

        case GPIO_InterruptMode_EdgeBoth:
            GPIOx->INTMODE |= pins;
            GPIOx->INTPOL |= pins;
            GPIOx->DUALEDGE |= pins;
            break;

        default:
            break;
    }
}

/* EOF. */

